package general.datastructures;

/**
 * Class which is used to store {@link Waypoint}s in a {@link PriorityQueue}
 * 
 * @version 0.4.1
 * @since 0.4.0
 * 
 * @see PriorityQueue
 * 
 * @author Tim
 */
public class PriorityNode implements Comparable<PriorityNode>{
	
	private double priority;
	private Waypoint wp;
	
	private PriorityNode next;
	
	/**
	 * Constructor for a Node
	 * 
	 * @param priority Priority of the {@link Waypoint}. A lower value means, that this object will be stored closer to the head 
	 * @param wp The stored {@link Waypoint}
	 */
	public PriorityNode(double priority, Waypoint wp)
	{
		this.priority = priority;
		this.wp = wp;
	}
	
	/**
	 * Constructor for a Node
	 * 
	 * @param priority Priority of the {@link Waypoint}. A lower value means, that this object will be stored closer to the head 
	 * @param wp The stored {@link Waypoint}
	 * @param next The successing {@link PriorityNode}
	 */
	public PriorityNode(double priority, Waypoint wp, PriorityNode next)
	{
		this.priority = priority;
		this.wp = wp;
		this.next = next;
	}
	
	
	/**
	 * 
	 * @return The priority of this Node
	 */
	public double getPriority()
	{
		return this.priority;
	}
	
	/**
	 * 
	 * @return The {@link Waypoint} stored in this Node
	 */
	public Waypoint getWaypoint()
	{
		return this.wp;
	}
	
	/**
	 * 
	 * @return The successing Node
	 */
	public PriorityNode getNext()
	{
		return this.next;
	}
	
	/**
	 * Sets the successing Node
	 * 
	 * @param node The successing Node
	 */
	public void setNext(PriorityNode node)
	{
		this.next = node;
	}
	
	/**
	 * Checks if this Node or any successing Node contains the wp, working recursive
	 * 
	 * @param wp {@link Waypoint} which is searched for
	 * @return True, if this, or any succeding {@link PriorityNode} contains the passed {@link Waypoint}
	 */
	public boolean contains(Waypoint wp)
	{
		return (this.wp.equals(wp)) ? true : ((next==null) ? false : next.contains(wp));
	}
	
	/**
	 *   Stores the passed {@link Waypoint} in the {@link PriorityQueue}, ordered by the priority. A lower value means, 
	 *   that this object will be stored closer to the head. If the {@link Waypoint} is already stored in the {@link PriorityQueue}
	 *   the entry will be updated, if the priority of the passed {@link Waypoint} is lower than the existing one
	 *   
	 * @param wp The stored {@link Waypoint}
	 * @param priority Priority of the {@link Waypoint}.
	 * @return returns if the passed waypoint has to be inserted in the place of this {@link PriorityNode} 
	 */
	public boolean insert(double priority, Waypoint wp)
	{
		if (this.priority < priority)
		{
			if((this.next==null)||(next.insert(priority, wp)))
			{
				this.next = new PriorityNode(priority, wp, this.next);
				try
				{
					this.next.remove(wp);
				}
				catch (NullPointerException ex){}
			}
			return false;
		}
		else
		{
			return true;
		}
	}
	
	/**
	 * Returns the Distance from the root {@link Waypoint} to the {@link Waypoint} containing the wp, working recursive
	 * 
	 * @param wp {@link Waypoint} whose distance 
	 * @return the Distance, if no {@link Waypoint} contains the passed wp, <code>Double.MAX_VALUE</code> is returned
	 */
	public double getDistanceTo(Waypoint wp)
	{
		
		if (this.wp.equals(wp))
		{
			return this.wp.getDistance();
		}
		else
		{
			return (next==null) ? Double.MAX_VALUE : next.getDistanceTo(wp);
		}
	}
	
	/**
	 * Removes the Node which contains the passed {@link Waypoint} recursively
	 * 
	 * @param wp The {@link Waypoint} which shall be deleted
	 * @return True, if the Node was deleted, False, if the wp was not found
	 */
	public boolean remove(Waypoint wp)
	{
		try{
		
			if (next.wp.equals(wp))
			{
				next = next.next;
				return true;
			}
			else
			{
				return (next==null) ? false : next.remove(wp);
			}
		
		}
		catch (NullPointerException e) {
			return false;
		}
	}

	/**
	 * @see Comparable
	 */
	@Override
	public int compareTo(PriorityNode arg0) {
		if (this.priority < arg0.priority)
		{
			return -1;
		}
		else if(this.priority > arg0.priority)
		{
			return 1;
		}
		else
		{
			return 0;
		}
	}
	
	/**
	 * @see Object
	 */
	@Override
	public boolean equals(Object obj) {
		return this.wp.equals(((PriorityNode)obj).wp);
	}

	/**
	 * Prints out all information stored in this PriorityNode, including the data of the contained {@link Waypoint}
	 */
	@Override
	public String toString() {
		return "Priority: "+priority+" wp: "+wp.toString() + "Next element available? " + (next!=null);
	}
	
}
